/*
 * Overlays - Images, text or other things that can be rendered over the top of a ListView
 *
 * Author: Phillip Piper
 * Date: 14/04/2009 4:36 PM
 *
 * Change log:
 * v2.3
 * 2009-08-17   JPP  - Overlays now use Adornments
 *                   - Added ITransparentOverlay interface. Overlays can now have separate transparency levels
 * 2009-08-10   JPP  - Moved decoration related code to new file
 * v2.2.1
 * 200-07-24    JPP  - TintedColumnDecoration now works when last item is a member of a collapsed
 *                     group (well, it no longer crashes).
 * v2.2
 * 2009-06-01   JPP  - Make sure that TintedColumnDecoration reaches to the last item in group view
 * 2009-05-05   JPP  - Unified BillboardOverlay text rendering with that of TextOverlay
 * 2009-04-30   JPP  - Added TintedColumnDecoration
 * 2009-04-14   JPP  - Initial version
 *
 * To do:
 *
 * Copyright (C) 2009-2014 Phillip Piper
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * If you wish to use this code in a closed source application, please contact phillip.piper@gmail.com.
 */

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Fluent.Lists;

namespace Fluent {
	/// <summary>
	/// The interface for an object which can draw itself over the top of
	/// an FluentListView.
	/// </summary>
	public interface IOverlay {
		/// <summary>
		/// Draw this overlay
		/// </summary>
		/// <param name="olv">The FluentListView that is being overlaid</param>
		/// <param name="g">The Graphics onto the given OLV</param>
		/// <param name="r">The content area of the OLV</param>
		void Draw(AdvancedListView olv, Graphics g, Rectangle r);
	}

	/// <summary>
	/// An interface for an overlay that supports variable levels of transparency
	/// </summary>
	public interface ITransparentOverlay : IOverlay {
		/// <summary>
		/// Gets or sets the transparency of the overlay. 
		/// 0 is completely transparent, 255 is completely opaque.
		/// </summary>
		int Transparency { get; set; }
	}

	/// <summary>
	/// A null implementation of the IOverlay interface
	/// </summary>
	public class AbstractOverlay : ITransparentOverlay {
		#region IOverlay Members

		/// <summary>
		/// Draw this overlay
		/// </summary>
		/// <param name="olv">The FluentListView that is being overlaid</param>
		/// <param name="g">The Graphics onto the given OLV</param>
		/// <param name="r">The content area of the OLV</param>
		public virtual void Draw(AdvancedListView olv, Graphics g, Rectangle r) {
		}

		#endregion

		#region ITransparentOverlay Members

		/// <summary>
		/// How transparent should this overlay be?
		/// </summary>
		[Category("FluentListView")]
		[Description("How transparent should this overlay be")]
		[DefaultValue(128)]
		[NotifyParentProperty(true)]
		public int Transparency {
			get => transparency;
			set => transparency = Math.Min(255, Math.Max(0, value));
		}

		private int transparency = 128;

		#endregion
	}

	/// <summary>
	/// An overlay that will draw an image over the top of the FluentListView
	/// </summary>
	[TypeConverter("Fluent.Design.OverlayConverter")]
	public class ImageOverlay : ImageAdornment, ITransparentOverlay {
		/// <summary>
		/// Create an ImageOverlay
		/// </summary>
		public ImageOverlay() {
			Alignment = ContentAlignment.BottomRight;
		}

		#region Public properties

		/// <summary>
		/// Gets or sets the horizontal inset by which the position of the overlay will be adjusted
		/// </summary>
		[Category("FluentListView")]
		[Description("The horizontal inset by which the position of the overlay will be adjusted")]
		[DefaultValue(20)]
		[NotifyParentProperty(true)]
		public int InsetX {
			get => insetX;
			set => insetX = Math.Max(0, value);
		}

		private int insetX = 20;

		/// <summary>
		/// Gets or sets the vertical inset by which the position of the overlay will be adjusted
		/// </summary>
		[Category("FluentListView")]
		[Description("Gets or sets the vertical inset by which the position of the overlay will be adjusted")]
		[DefaultValue(20)]
		[NotifyParentProperty(true)]
		public int InsetY {
			get => insetY;
			set => insetY = Math.Max(0, value);
		}

		private int insetY = 20;

		#endregion

		#region Commands

		/// <summary>
		/// Draw this overlay
		/// </summary>
		/// <param name="olv">The FluentListView being decorated</param>
		/// <param name="g">The Graphics used for drawing</param>
		/// <param name="r">The bounds of the rendering</param>
		public virtual void Draw(AdvancedListView olv, Graphics g, Rectangle r) {
			var insetRect = r;
			insetRect.Inflate(-InsetX, -InsetY);

			// We hard code a transparency of 255 here since transparency is handled by the glass panel
			DrawImage(g, insetRect, Image, 255);
		}

		#endregion
	}

	/// <summary>
	/// An overlay that will draw text over the top of the FluentListView
	/// </summary>
	[TypeConverter("Fluent.Design.OverlayConverter")]
	public class TextOverlay : TextAdornment, ITransparentOverlay {
		/// <summary>
		/// Create a TextOverlay
		/// </summary>
		public TextOverlay() {
			Alignment = ContentAlignment.BottomRight;
		}

		#region Public properties

		/// <summary>
		/// Gets or sets the horizontal inset by which the position of the overlay will be adjusted
		/// </summary>
		[Category("FluentListView")]
		[Description("The horizontal inset by which the position of the overlay will be adjusted")]
		[DefaultValue(20)]
		[NotifyParentProperty(true)]
		public int InsetX {
			get => insetX;
			set => insetX = Math.Max(0, value);
		}

		private int insetX = 20;

		/// <summary>
		/// Gets or sets the vertical inset by which the position of the overlay will be adjusted
		/// </summary>
		[Category("FluentListView")]
		[Description("Gets or sets the vertical inset by which the position of the overlay will be adjusted")]
		[DefaultValue(20)]
		[NotifyParentProperty(true)]
		public int InsetY {
			get => insetY;
			set => insetY = Math.Max(0, value);
		}

		private int insetY = 20;

		/// <summary>
		/// Gets or sets whether the border will be drawn with rounded corners
		/// </summary>
		[Browsable(false)]
		[Obsolete("Use CornerRounding instead", false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool RoundCorneredBorder {
			get => CornerRounding > 0;
			set {
				if (value) {
					CornerRounding = 16.0f;
				}
				else {
					CornerRounding = 0.0f;
				}
			}
		}

		#endregion

		#region Commands

		/// <summary>
		/// Draw this overlay
		/// </summary>
		/// <param name="olv">The FluentListView being decorated</param>
		/// <param name="g">The Graphics used for drawing</param>
		/// <param name="r">The bounds of the rendering</param>
		public virtual void Draw(AdvancedListView olv, Graphics g, Rectangle r) {
			if (string.IsNullOrEmpty(Text)) {
				return;
			}

			var insetRect = r;
			insetRect.Inflate(-InsetX, -InsetY);

			// We hard code a transparency of 255 here since transparency is handled by the glass panel
			DrawText(g, insetRect, Text, 255);
		}

		#endregion
	}

	/// <summary>
	/// A Billboard overlay is a TextOverlay positioned at an absolute point
	/// </summary>
	public class BillboardOverlay : TextOverlay {
		/// <summary>
		/// Create a BillboardOverlay
		/// </summary>
		public BillboardOverlay() {
			Transparency = 255;
			BackColor = Color.PeachPuff;
			TextColor = Color.Black;
			BorderColor = Color.Empty;
			Font = new Font("Tahoma", 10);
		}

		/// <summary>
		/// Gets or sets where should the top left of the billboard be placed
		/// </summary>
		public Point Location {
			get => location;
			set => location = value;
		}

		private Point location;

		/// <summary>
		/// Draw this overlay
		/// </summary>
		/// <param name="olv">The FluentListView being decorated</param>
		/// <param name="g">The Graphics used for drawing</param>
		/// <param name="r">The bounds of the rendering</param>
		public override void Draw(AdvancedListView olv, Graphics g, Rectangle r) {
			if (string.IsNullOrEmpty(Text)) {
				return;
			}

			// Calculate the bounds of the text, and then move it to where it should be
			var textRect = CalculateTextBounds(g, r, Text);
			textRect.Location = Location;

			// Make sure the billboard is within the bounds of the List, as far as is possible
			if (textRect.Right > r.Width) {
				textRect.X = Math.Max(r.Left, r.Width - textRect.Width);
			}

			if (textRect.Bottom > r.Height) {
				textRect.Y = Math.Max(r.Top, r.Height - textRect.Height);
			}

			DrawBorderedText(g, textRect, Text, 255);
		}
	}
}